package com.hjy.elasticsearch.elasticsearch.service.impl;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.hjy.elasticsearch.elasticsearch.service.ESService;
import com.hjy.elasticsearch.service.impl.CityESServiceImpl;
import com.hjy.elasticsearch.util.CommConstant;
import com.hjy.elasticsearch.util.DateUtil;
import com.hjy.elasticsearch.util.StringUtil;
import io.searchbox.core.*;
import io.searchbox.indices.DeleteIndex;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import io.searchbox.client.JestClient;
import io.searchbox.client.JestResult;

import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;

@Service
public class ESServiceImpl<T> implements ESService<T>{

    private static final Logger LOGGER = LoggerFactory.getLogger(ESServiceImpl.class);

    @Autowired
    private JestClient jestClient;

    /**
     * 单个(更新)新增，注意：保存的实体类中的date必须转换成时间戳
     * ES中的时间保存，是按照时区来存储的，相对麻烦
     */
    @Override
    public Index saveEntity(T t) {
        String string = t.getClass().getName();
        String[] str = string.split("\\.");
        String ss = str[str.length-1].toLowerCase()+CommConstant.ES_INDEX_NAME;

        Index index = new Index.Builder(t).index(ss).type(CommConstant.ES_TYPE).build();
        try {
            jestClient.execute(index);
            LOGGER.info("ES 单个插入完成");
            return  index;
        } catch (IOException e) {
            e.printStackTrace();
            LOGGER.error("ES 单个插入失败，e={}",e.getMessage());
            return null;
        }
    }

    /**
     * 批量新增，注意：保存的实体类中的date必须转换成时间戳
     * ES中的时间保存，是按照时区来存储的，相对麻烦
     */
    @Override
    public void saveEntity(List<T> entityList) {
        Bulk.Builder bulk = new Bulk.Builder();
        for(T entity : entityList) {
            String string = entity.getClass().getName();
            String[] str = string.split("\\.");
            String ss = str[str.length-1].toLowerCase()+CommConstant.ES_INDEX_NAME;

            Index index = new Index.Builder(entity).index(ss).type(CommConstant.ES_TYPE).build();
            bulk.addAction(index);
        }
        try {
            jestClient.execute(bulk.build());
            LOGGER.info("ES 批量插入完成,条数："+entityList.size());
        } catch (IOException e) {
            e.printStackTrace();
            LOGGER.error("ES 批量插入失败，e={}",e.getMessage());
        }

    }

    /**
     * 多列查询
     */
    @Override
    public Object searchmore(T t,String searchContent, String... index) {
        long bigintime = System.currentTimeMillis();
        String string = t.getClass().getName();
        String[] str = string.split("\\.");
        String ss = str[str.length-1].toLowerCase()+CommConstant.ES_INDEX_NAME;

        QueryBuilder queryBuilder = QueryBuilders.multiMatchQuery(searchContent, index);

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(queryBuilder);

        Search search = new Search.Builder(searchSourceBuilder.toString())
                .addIndex(ss).addType(CommConstant.ES_TYPE).build();
        try {
            JestResult result = jestClient.execute(search);
            long endtime = System.currentTimeMillis();
            LOGGER.info("ES多列查询成功,T={},searchContent={},耗时={}",t,searchContent,endtime-bigintime);
            return result.getSourceAsObjectList(t.getClass());
        } catch (IOException e) {
            long endtime = System.currentTimeMillis();
            LOGGER.error("ES多列查询失败,T={},searchContent={},耗时={},e={}",t,searchContent,endtime-bigintime,e.getMessage());
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 分页查询
     * @param t
     * @param pageNumber:第几页，从一开始
     * @param pageSize:每页数量
     * @param sort:排序的字段
     * @param order:SortOrder.DESC  SortOrder.ASC
     * @param searchContent：查询数据
     * @param index：查询的列
     * @return
     */
    public Map searchPage(T t, int pageNumber, int pageSize, String sort, SortOrder order, String searchContent, String... index){
        long bigintime = System.currentTimeMillis();
        String string = t.getClass().getName();
        String[] str = string.split("\\.");
        String ss = str[str.length-1].toLowerCase()+CommConstant.ES_INDEX_NAME;
        Map<String, Object> returnMap = new HashMap<String, Object>();

        QueryBuilder queryBuilders = QueryBuilders.multiMatchQuery(searchContent, index);

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(queryBuilders);

        if(pageNumber>=1 && pageSize>0){
            searchSourceBuilder.from((pageNumber - 1) * pageSize);//设置起始页
            searchSourceBuilder.size(pageSize);//设置页大小
        }
        if(!StringUtil.isBlank(sort) && order != null){
            searchSourceBuilder.sort(sort, order);//排序
        }

        Search search = new Search.Builder(searchSourceBuilder.toString())
                .addIndex(ss).addType(CommConstant.ES_TYPE).build();
        try {
            JestResult result = jestClient.execute(search);
            int hitCount = result.getJsonObject().get("hits").getAsJsonObject().get("total").getAsInt();//总条数
            int totalPages = 0;
            if(hitCount%pageSize==0){
                totalPages=hitCount / pageSize;
            }else{
                totalPages=(hitCount / pageSize) + 1;
            }

            returnMap.put("content", result.getSourceAsObjectList(t.getClass()));
            returnMap.put("number", pageNumber - 1);//第几页
            returnMap.put("numberOfElements", pageSize);//本页的数量
            returnMap.put("totalElements", hitCount);//总条数
            returnMap.put("totalPages", totalPages);//总页数

            long endtime = System.currentTimeMillis();
            LOGGER.info("ES多列分页排序查询成功,T={},searchContent={},sort={},耗时={}",t,searchContent,sort,endtime-bigintime);
            return returnMap;
        } catch (IOException e) {
            long endtime = System.currentTimeMillis();
            LOGGER.error("ES多列分页排序查询失败,T={},searchContent={},sort={},耗时={},e={}",t,searchContent,sort,endtime-bigintime,e.getMessage());
            e.printStackTrace();
        }
        return returnMap;

    }
    /**
     * 区间查询(不能查时间)
     * @param t：实体类
     * @param pageNumber：第几页，从一开始
     * @param pageSize:每页数量
     * @param sort:排序的字段
     * @param order:SortOrder.DESC  SortOrder.ASC
     * @param beginCompare:开始数据
     * @param endCompare：结束数据
     * @param index:字段
     * @return
     */
    public Map searchSectionPage(T t,int pageNumber,int pageSize,String sort,SortOrder order,String beginCompare, String endCompare,String index){
        long bigintime = System.currentTimeMillis();
        String string = t.getClass().getName();
        String[] str = string.split("\\.");
        String ss = str[str.length-1].toLowerCase()+CommConstant.ES_INDEX_NAME;
        Map<String, Object> returnMap = new HashMap<String, Object>();

        QueryBuilder queryBuilders = QueryBuilders
                .rangeQuery(index)
                .gte(beginCompare)
                .lte(endCompare)
                .includeLower(true)
                .includeUpper(true);//区间查询

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(queryBuilders);

        if(pageNumber>=1 && pageSize>0){
            searchSourceBuilder.from((pageNumber - 1) * pageSize);//设置起始页
            searchSourceBuilder.size(pageSize);//设置页大小
        }
        if(!StringUtil.isBlank(sort) && order != null){
            searchSourceBuilder.sort(sort, order);//排序
        }

        Search search = new Search.Builder(searchSourceBuilder.toString())
                .addIndex(ss).addType(CommConstant.ES_TYPE).build();
        try {
            JestResult result = jestClient.execute(search);
            int hitCount = result.getJsonObject().get("hits").getAsJsonObject().get("total").getAsInt();//总条数
            int totalPages = 0;
            if(hitCount%pageSize==0){
                totalPages=hitCount / pageSize;
            }else{
                totalPages=(hitCount / pageSize) + 1;
            }
            returnMap.put("content", result.getSourceAsObjectList(t.getClass()));
            returnMap.put("number", pageNumber - 1);//第几页
            returnMap.put("numberOfElements", pageSize);//本页的数量
            returnMap.put("totalElements", hitCount);//总条数
            returnMap.put("totalPages", totalPages);//总页数

            long endtime = System.currentTimeMillis();
            LOGGER.info("ES分页排序区间查询成功,T={},beginCompare={},endCompare={},index={},sort={},耗时={}",t,beginCompare,endCompare,index,sort,endtime-bigintime);
            return returnMap;
        } catch (IOException e) {
            long endtime = System.currentTimeMillis();
            LOGGER.error("ES分页排序区间查询失败,T={},beginCompare={},endCompare={},index={},sort={},耗时={}",t,beginCompare,endCompare,index,sort,endtime-bigintime);
            e.printStackTrace();
        }
        return returnMap;

    }
    /**
     * 时间区间查询(只能查时间)
     * @param t：实体类
     * @param pageNumber：第几页，从一开始
     * @param pageSize:每页数量
     * @param sort:排序的字段
     * @param order:SortOrder.DESC  SortOrder.ASC
     * @param beginCompare:开始数据
     * @param endCompare：结束数据
     * @param index:字段
     * @return
     */
    public Map searchSectionPageByDate(T t,int pageNumber,int pageSize,String sort,SortOrder order,String beginCompare, String endCompare,String index){
        long bigintime = System.currentTimeMillis();
        String string = t.getClass().getName();
        String[] str = string.split("\\.");
        String ss = str[str.length-1].toLowerCase()+CommConstant.ES_INDEX_NAME;
        Map<String, Object> returnMap = new HashMap<String, Object>();

        Long s1 =null;
        Long s2 =null;
        try {
            s1 = DateUtil.strToDateCom(beginCompare,DateUtil.TIME_PATTON_DEFAULT).getTime();
            s2 = DateUtil.strToDateCom(endCompare,DateUtil.TIME_PATTON_DEFAULT).getTime();
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        QueryBuilder queryBuilders = QueryBuilders
                .rangeQuery(index)
                .gte(s1)
                .lte(s2)
                .includeLower(true)//保含上区间
                .includeUpper(true);//保含下区间


        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(queryBuilders);

        if(pageNumber>=1 && pageSize>0){
            searchSourceBuilder.from((pageNumber - 1) * pageSize);//设置起始页
            searchSourceBuilder.size(pageSize);//设置页大小
        }
        if(!StringUtil.isBlank(sort) && order != null){
            searchSourceBuilder.sort(sort, order);//排序
        }

        Search search = new Search.Builder(searchSourceBuilder.toString())
                .addIndex(ss).addType(CommConstant.ES_TYPE).build();
        try {
            JestResult result = jestClient.execute(search);

            int hitCount = result.getJsonObject().get("hits").getAsJsonObject().get("total").getAsInt();//总条数
            int totalPages = 0;
            if(hitCount%pageSize==0){
                totalPages=hitCount / pageSize;
            }else{
                totalPages=(hitCount / pageSize) + 1;
            }
            returnMap.put("content", result.getSourceAsObjectList(t.getClass()));
            returnMap.put("number", pageNumber - 1);//第几页
            returnMap.put("numberOfElements", pageSize);//本页的数量
            returnMap.put("totalElements", hitCount);//总条数
            returnMap.put("totalPages", totalPages);//总页数

            long endtime = System.currentTimeMillis();
            LOGGER.info("ES分页排序时间区间查询成功,T={},beginCompare={},endCompare={},index={},sort={},耗时={}",t,beginCompare,endCompare,index,sort,endtime-bigintime);
            return returnMap;
        } catch (IOException e) {
            long endtime = System.currentTimeMillis();
            LOGGER.error("ES分页排序时间区间查询失败,T={},beginCompare={},endCompare={},index={},sort={},耗时={}",t,beginCompare,endCompare,index,sort,endtime-bigintime);
            e.printStackTrace();
        }
        return returnMap;

    }

    /**
     * 根据ID删除，若ID为null,则删除Document
     * @param t
     * @param id
     * @return
     */
    public boolean delete(T t,String id){
        String string = t.getClass().getName();
        String[] str = string.split("\\.");
        String ss = str[str.length-1].toLowerCase()+CommConstant.ES_INDEX_NAME;
        DocumentResult dr = null;
        try {
            dr = jestClient.execute(new Delete.Builder(id).index(ss).type(CommConstant.ES_TYPE).build());
            return dr.isSucceeded();
        }catch (IOException e){
           e.printStackTrace();
           return false;
        }
    }

    /**
     * 根据索引删除
     * @param t
     * @return
     */
    public boolean deleteIndex(T t){
        String string = t.getClass().getName();
        String[] str = string.split("\\.");
        String ss = str[str.length-1].toLowerCase()+CommConstant.ES_INDEX_NAME;

        JestResult jr = null;
        try {
            jr = jestClient.execute(new DeleteIndex.Builder(ss).build());
            return jr.isSucceeded();
        }catch (IOException e){
            e.printStackTrace();
            return false;
        }
    }


}
